###############################################################
## MOVE AND PLAY
## This programs starts playing music when motion is detected.
## When movement stops, music pauses.
## When movement continues, music continues.
###############################################################

import time, subprocess, getopt, sys
import RPi.GPIO as gpio

# use BCM pin numbers
gpio.setmode(gpio.BCM)
gpio.setwarnings(False)

# The pin that reads input signals from motion sensor
PIR_IN = 14
gpio.setup(PIR_IN, gpio.IN)


def main():
    try:
        # Read user-defined time before starting motion detection. Default is 5 seconds
        s_input = readArgument("-s");
        delay_time = 5 if (s_input is None) else float(s_input)
        
        # Read user-defined no-motion timeout. Default is 10 seconds
        t_input = readArgument("-t");
        noMotionTimeout = 10 if (t_input is None) else float(t_input)
        
        # Since it's directly connected to power, the sensor is already on.
        # Ignore the reading for the duration of delay_time.
        # After that, motion detection "officially" starts 
        log('No-motion timeout is set to ' + str(noMotionTimeout) + ' seconds') 
        log('Motion detection will start in ' + str(delay_time) + ' seconds') 
        time.sleep(delay_time) 
        log('Starting motion detection...') 

        createPlaylist() 
        
        # Control Parameters 
        noMotionTimeout = 10
        timeoutStartTime = 0
        timeoutCountStarted = False
        musicPlaying = False
        musicStartedBefore = False 
        
        while True:
            # motion detected
            if gpio.input(PIR_IN):
                # if music not playing yet, play
                if not musicPlaying:
                    log('Motion Detected. Music playing...')
                    playMusic()
                    musicPlaying = True
                    musicStartedBefore = True
                
                timeoutCountStarted = False
                
            # no motion detected
            else:
                # try pausing only music is playing
                if musicPlaying:
                    if not timeoutCountStarted:
                        startTime = time.time()
                        timeoutCountStarted = True
                    else:
                        # pause only if 'no motion' timeout has been reached
                        expiredTime = time.time() - startTime 
                        if expiredTime >= noMotionTimeout:
                            pauseMusic()
                            musicPlaying = False
            
            # if music has been started before,
            # quit if no song is currently playing 
            if musicStartedBefore:
                current = subprocess.check_output('mpc current', shell=True)
                if current is None or len(current) == 0:
                    log('The playlist has finished')
                    break
             
            time.sleep(1)
                    

    except KeyboardInterrupt:
        log('Program stopped by user.')
        stopMusic()
        gpio.cleanup()


def createPlaylist():
    run('mpc clear -q')
    
    # Read playlist file
    for line in open("playlist.txt", "r"):
        line = line.strip() 
        if not line.startswith('#') and len(line) > 0:
            try:
                proc('mpc add \'' + line + '\'') 
            except subprocess.CalledProcessError:
                print ('music file not found: ' + line)

def playMusic():
    run('mpc play -q')

def pauseMusic():
    run('mpc pause -q')

def stopMusic():
    run('mpc stop -q')
    run('mpc clear -q')


# Execute shell command
def run(command):
    subprocess.call(command, shell=True)

# Execute shell command, return output
def proc(command):
    return subprocess.check_output(command, shell=True)

# Read command-line argument of the given option
def readArgument(option):
    opts, args = getopt.getopt(sys.argv[1:], "s:t:")
    for opt, arg in opts:
        if opt == option:
            return arg


def log(logmsg):
    print("{}\t{}".format(time.strftime("%Y-%m-%d %H:%M:%S"), logmsg))

if __name__=="__main__":main()
